/*!
 *  \file       WrapNumber.cpp
 *  \brief      Implementazione della classe \c WrapNumber
 *  \author     Davide Scola <S2299453@studenti.unige.it>
 *  \author		Minetti Alberto <S3064777@studenti.unige.it>
 *  \version    1.0
 *
 */


#include <cmath>
#include <iostream>
#include "WrapNumber.hpp"
#include "DivisionByZeroException.hpp"

using namespace std;


template < typename numberType >
WrapNumber< numberType >::WrapNumber( void )
{
    this->number_ = 0;
}

template < typename numberType >
WrapNumber< numberType >::WrapNumber( const numberType number )
{
    this->number_ = number;
}

template < typename numberType >
WrapNumber< numberType >::WrapNumber( const WrapNumber &other )
{
    *this = other;
}


/*!
 *  \brief      Operatore di assegnazione della classe \c WrapNumber
 *
 */
template < typename numberType > WrapNumber< numberType >&
WrapNumber< numberType >::operator=( const WrapNumber& other )
{
   if (this == &other) {
       return *this;
   }
   
   this->number_ = (&other)->number_;
   return *this;
}


/*!
 *  \brief      Operatore di addizione della classe \c WrapNumber
 *
 */
template < typename numberType > WrapNumber< numberType >
WrapNumber< numberType >::operator+( const WrapNumber& other )
{
    return WrapNumber( this->number_ + (&other)->number_ );
}

/*!
 *  \brief      Operatore di sottrazione della classe \c WrapNumber
 *
 */
template < typename numberType > WrapNumber< numberType >
WrapNumber< numberType >::operator-( const WrapNumber& other )
{
    return WrapNumber( this->number_ - (&other)->number_ );
}


/*!
 *  \brief      Operatore di moltiplicazione della classe \c WrapNumber
 *
 */
template < typename numberType > WrapNumber< numberType >
WrapNumber< numberType >::operator*( const WrapNumber& other )
{
    return WrapNumber( this->number_ * (&other)->number_ );
}


/*!
 *  \brief      Operatore di divisione della classe \c WrapNumber
 *
 */
template < typename numberType > WrapNumber< numberType >
WrapNumber< numberType >::operator/( const WrapNumber& other )
{
    if( other == WrapNumber< numberType >( 0 ) ) {
        throw DivisionByZeroException( );
    }
    
    return WrapNumber( this->number_ / (&other)->number_ );
}


template < typename numberType > WrapNumber< numberType >&
WrapNumber< numberType >::operator+=( const WrapNumber& other )
{
    this->number_ += (&other)->number_;
    return *this;
}

template < typename numberType > WrapNumber< numberType >&
WrapNumber< numberType >::operator-=( const WrapNumber& other )
{
    this->number_ -= (&other)->number_;
    return *this;
}

template < typename numberType > WrapNumber< numberType >&
WrapNumber< numberType >::operator*=( const WrapNumber& other )
{
    this->number_ *= (&other)->number_;
    return *this;
}

template < typename numberType > WrapNumber< numberType >&
WrapNumber< numberType >::operator/=( const WrapNumber& other )
{
    this->number_ /= (&other)->number_;
    return *this;
}


/*!
 *  \brief      Operatore di uguaglianza della classe \c WrapNumber
 *
 */
template < typename numberType > bool
WrapNumber< numberType >::operator==( const WrapNumber& other ) const
{
    return this->number_ == (&other)->number_;
}


/*!
 *  \brief      Operatore di diseguaglianza della classe \c WrapNumber
 *
 */
template < typename numberType > bool
WrapNumber< numberType >::operator!=( const WrapNumber& other ) const
{
    return !( *this == other );
}


/*!
 *  \brief      Operatore di confronto (minore) della classe \c WrapNumber
 *
 */
template < typename numberType > bool
WrapNumber< numberType >::operator<( const WrapNumber& other ) const
{
    return ( *this != other ) && ( this->number_ < (&other)->number_ );
}


/*!
 *  \brief      Operatore di confronto (maggiore) della classe \c WrapNumber
 *
 */
template < typename numberType > bool
WrapNumber< numberType >::operator>( const WrapNumber& other ) const
{
    return ( *this != other ) && ( this->number_ > (&other)->number_ );
}


/*!
 *  \brief      Operatore di confronto (minore od uguale) della classe \c WrapNumber
 *
 */
template < typename numberType > bool
WrapNumber< numberType >::operator<=( const WrapNumber& other ) const
{
    return !( *this > other );
}

/*!
 *  \brief      Operatore di confronto (maggiore od uguale) della classe \c WrapNumber
 *
 */
template < typename numberType > bool
WrapNumber< numberType >::operator>=( const WrapNumber& other ) const
{
    return !( *this < other );
}


/*!
 *  \brief      Operatore di casting al tipo primitivo della classe \c WrapNumber
 */
template < typename numberType >
WrapNumber< numberType >::operator numberType( void ) const
{
  return static_cast< numberType >( this->number_ );
}


/*!
 *  \brief      Getter della classe \c WrapNumber
 *
 */
template < typename numberType > numberType
WrapNumber< numberType >::value( void ) const
{
    return this->number_;
}


/*!
 *  \brief      Operatore di output della classe \c WrapNumber
 *
 */
template < typename numberType > ostream&
operator<<( ostream& out, const WrapNumber< numberType >& obj )
{
    out << (&obj)->value();
    return out;
}

/*!
 *  \brief      Operatore di input della classe \c WrapNumber
 *
 */
template < typename numberType > istream&
operator>>( istream& in, WrapNumber< numberType >& obj )
{
  numberType swap;
  
  in >> swap;
  obj = WrapNumber< numberType >( swap );
  
  return in;
}
